package aorm

import (
	"gitee.com/KotlinToGo/aorm/dialect"
	"go/ast"
	"reflect"
)

var (
	TagKey string
	Ignore string
)

// 表中的字段
type Field struct {
	Name string // 字段名
	Type string // 字段类型
	Tag string  // 字段约束，例如: primary key，unique ...
}

// 对象和表的映射
type Schema struct {
	Model interface{}   // 模型对象
	Name string         // 表名
	Fields []*Field     // 表中所有字段
	FieldNames []string // 表中所有字段的名字
	fieldMap map[string]*Field
}

func (s *Schema) GetField (name string) *Field {
	return s.fieldMap[name]
}

// Parse 将任意的对象解析为 Schema 实例，TagName 定义在engine.go 文件里。
func (s *Schema) Parse(dest interface{}, d dialect.Dialect) *Schema {
	// reflect.Indirect(v Value) 返回v指向的值。如果v是nil指针，则Indirect返回零值。如果v不是指针，则Indirect返回v。
	modelType := reflect.Indirect(reflect.ValueOf(dest)).Type()
	schema := &Schema{
		Model:    dest,
		Name:     modelType.Name(), // 将结构体名赋值给表名。
		fieldMap: make(map[string]*Field),
	}

	for i := 0; i < modelType.NumField(); i++ {
		p := modelType.Field(i)

		if !p.Anonymous && ast.IsExported(p.Name) {//如果p不是匿名字段，并且p的字段名是以大写字母开头。
			field := &Field{
				Name: p.Name,
				Type: d.Convert(reflect.Indirect(reflect.New(p.Type))),
				//Type: Convert(reflect.Indirect(reflect.New(p.Type))),
			}
			if v, ok := p.Tag.Lookup(TagKey); ok {
				field.Tag = v
			}

			schema.Fields = append(schema.Fields, field)
			schema.FieldNames = append(schema.FieldNames, p.Name)
			schema.fieldMap[p.Name] = field
		}
	}
	return schema
}

// FieldValues 获取结构体中所有字段的值，参数<dest>为 struct/*struct。
func (s *Schema) FieldValues(dest interface{}) []interface{} {
	destValue := reflect.Indirect(reflect.ValueOf(dest))
	var fieldValues []interface{}
	for _, field := range s.Fields {
		fieldValues = append(fieldValues, destValue.FieldByName(field.Name).Interface())
	}
	return fieldValues
}
